package ar.com.arkios.kfcon4d;

import ar.com.arkios.kfcon4d.exception.Open4DException;
import ar.com.arkios.kfcon4d.util.EstructuraUtil;
import ar.com.arkios.j4d.opConnection;
import ar.com.arkios.j4d.opDriverManager;
import ar.com.arkios.j4d.opException;
import ar.com.arkios.j4d.opProcess;
import ar.com.arkios.j4d.opTable;
import java.net.UnknownHostException;
import ar.com.arkios.j4d.opTableArray;
import java.util.Hashtable;
import org.apache.log4j.Logger;

/**
 * Esta clase, implementada como SINGLETON, es la encargada de conectarse al 4D, abrir un proceso y armar diccionario
 * que relacione nombres de tablas con sus correspondientes números.
 * 
 * POR AHORA: solo se abre un proceso. De ser necesario más de uno se puede agregar un atributo array de procesos
 * 
 * En nro de ip y el puerto donde ubicar al server 4D van en un archivo de propiedades
 * 
 * @author wado
 */
public class Connection4D {
    
    private static final Logger miLogger = Logger.getLogger(Connection4D.class);
    
    private static Connection4D MyInstance = null;
    private static final String PCNAME = "DefaultName";
    private String user = "Arkios";
    private String passwd = "fruxtilla";
    private String pcName;
    private String procName = "KFConector";
    
    private opConnection myConnection = null;
    private opProcess myProcess = null;
    private Hashtable<String, opTable> miDiccionarioTablas4D;

    /**
     * 
     * 
     * @throws ar.com.arkios.kfcon4d.exception.Open4DException
     */
    private Connection4D() throws Open4DException {
        miLogger.info("Se inicia la conexión al servidor de 4D.");
        
        opDriverManager drvrManager = new opDriverManager();
        try {
            myConnection = drvrManager.getConnection (ConfigurationManager.getIpKFrux(),ConfigurationManager.getPortKFrux());
            miLogger.info("Conexión levantada.");
            try{
                pcName = ConfigurationManager.getPCName();
            }
            catch (UnknownHostException e){
                pcName = PCNAME;
            }
            miLogger.info("Inicio Proceso.");
            myProcess = myConnection.startProcess(pcName, user, passwd, procName);
            miLogger.info("+----------------------------------------------------+");
            miLogger.info("Se creo con éxito la conexión al servidor 4D");
            miLogger.info(" * Nombre de pc conectada: " + pcName);
            miLogger.info(" * Nombre de usuairo: " + user);
            miLogger.info(" * Nombre del proceso asociado: " + procName);
            miLogger.info("+----------------------------------------------------+");
            miLogger.info("Inicio Carga Estructura.");
            this.loadStructure();
        }
        catch (opException ex) {
            miLogger.error("Error al crear la conexión a servidor de 4D.");
            throw new Open4DException("Error al crear la conexión a la base de 4D", ex);
        }        
    }
    
    public static Connection4D getInstance() throws Open4DException {
        if (MyInstance == null)
            MyInstance = new Connection4D();
        return MyInstance;
    }
    
    public void closeConnection() throws Open4DException {
        try {
            myConnection.stopProcess(myProcess);
            myConnection.CloseConnection();
        } catch (opException e) {
            throw new Open4DException(e);
        }
    }
    
    private void loadStructure() throws opException {
        final short cantTablasKFrux = myProcess.CountTables();
        opTableArray tableArray = new opTableArray(cantTablasKFrux);
        myProcess.GetTableNames(tableArray);
        
        miDiccionarioTablas4D = new Hashtable<String, opTable>(cantTablasKFrux);
        for (String tableName : EstructuraUtil.misTablas4D) {
            opTable tabla = findTable(tableName, tableArray);
            myProcess.GetTableProperties(tabla);
            miDiccionarioTablas4D.put(tabla.mTableName, tabla);
        }
    }
    
    private opTable findTable(String tableName, opTableArray tableArray) {
        for (opTable tabla : tableArray.mTableArray) {
            if(tabla.mTableName.equals(tableName)) {
                return tabla;
            }
        }
        
        return null;
    }
    
    public opTable getTable(String tableName) {
        return miDiccionarioTablas4D.get(tableName);
    }
    
    public short getTableNumber (String tableName) {
        return miDiccionarioTablas4D.get(tableName).mTableNumber;
    }

    public opProcess getMyProcess() {
        return myProcess;
    }
/*    
    public static void main(String[] args) throws InterruptedException {
        boolean entrar = false;
System.out.println("Inicio");
//try {
//PalletDAO pdao = new PalletDAO();
//List<Pallet> lp = pdao.getPallet();
//BultosXEmbaDAO bxe = new BultosXEmbaDAO();
//List<BultoPorEmbalador> lb =  bxe.getBxE();}
//catch (opException e){}

        if (entrar) {
            try {
                ArrayList<Especie> laLista = simEspecies();
                EspecieDAO dao = new EspecieDAO();
                dao.saveAll(laLista);
            } catch (opException ex) {
                java.util.logging.Logger.getLogger(Connection4D.class.getName()).log(Level.SEVERE, null, ex);
            }
        }

        if (entrar) {
            try {
                ArrayList<Variedad> laLista = simVariedades();
                VariedadDAO dao = new VariedadDAO();
                dao.saveAll(laLista);
            } catch (opException ex) {
                java.util.logging.Logger.getLogger(Connection4D.class.getName()).log(Level.SEVERE, null, ex);
            }
        }

        if (entrar) {
            try {
                ArrayList<Envase> laLista = simEnvases();
                EnvaseDAO dao = new EnvaseDAO();
                dao.saveAll(laLista);
            } catch (opException ex) {
                java.util.logging.Logger.getLogger(Connection4D.class.getName()).log(Level.SEVERE, null, ex);
            }
        }

        if (entrar) {
            try {
                ArrayList<Calibre> laLista = simCalibres();
                CalibreDAO dao = new CalibreDAO();
                dao.saveAll(laLista);
            } catch (opException ex) {
                java.util.logging.Logger.getLogger(Connection4D.class.getName()).log(Level.SEVERE, null, ex);
            }
        }

        if (entrar) {
            try {
                ArrayList<Embalaje> laLista = simEmbalajes();
                EmbalajeDAO dao = new EmbalajeDAO();
                dao.saveAll(laLista);
            } catch (opException ex) {
                java.util.logging.Logger.getLogger(Connection4D.class.getName()).log(Level.SEVERE, null, ex);
            }
        }

        if (entrar) {
            try {
                ArrayList<Almacen> laLista = simAlmacenes();
                AlmacenDAO dao = new AlmacenDAO();
                dao.saveAll(laLista);
            } catch (opException ex) {
                java.util.logging.Logger.getLogger(Connection4D.class.getName()).log(Level.SEVERE, null, ex);
            }
        }

        if (entrar) {
            try {
                ArrayList<LeyendaEtiqueta> laLista = simLeyendas();
                LeyendaEtiquetaDAO dao = new LeyendaEtiquetaDAO();
                dao.saveAll(laLista);
            } catch (opException ex) {
                java.util.logging.Logger.getLogger(Connection4D.class.getName()).log(Level.SEVERE, null, ex);
            }
        }

        if (entrar) {
            try {
                ArrayList<CodigoEAN> laLista = simEAN();
                CodigoEANDAO dao = new CodigoEANDAO();
                dao.saveAll(laLista);
            } catch (opException ex) {
                java.util.logging.Logger.getLogger(Connection4D.class.getName()).log(Level.SEVERE, null, ex);
            }
        }

        if (entrar) {
            try {
                ArrayList<Contramarca> laLista = simContraMarca();
                ContramarcaDAO dao = new ContramarcaDAO();
                dao.saveAll(laLista);
            } catch (opException ex) {
                java.util.logging.Logger.getLogger(Connection4D.class.getName()).log(Level.SEVERE, null, ex);
            }
        }

        if (entrar) {
            try {
                ArrayList<PesoStandar> laLista = simPesosStd();
                PesoStandarDAO dao = new PesoStandarDAO();
                dao.saveAll(laLista);
            } catch (opException ex) {
                java.util.logging.Logger.getLogger(Connection4D.class.getName()).log(Level.SEVERE, null, ex);
            }
        }

        if (entrar) {
            try {
                ArrayList<Orden> laLista = simOrden();
                OrdenDAO dao = new OrdenDAO();
                dao.saveAll(laLista);
            } catch (opException ex) {
                java.util.logging.Logger.getLogger(Connection4D.class.getName()).log(Level.SEVERE, null, ex);
            }
        }

        if (entrar) {
            try {
                ArrayList<Lote> laLista = simLote();
                LoteDAO dao = new LoteDAO();
                dao.saveAll(laLista);
            } catch (opException ex) {
                java.util.logging.Logger.getLogger(Connection4D.class.getName()).log(Level.SEVERE, null, ex);
            }
        }
System.exit(0);
    }
    

    private static ArrayList<Especie> simEspecies() {
        int cuantos = 5000;
        Especie especie;
        ArrayList<Especie> laLista = new ArrayList<Especie>(cuantos);
        for (int i = 0; i < cuantos; i++) {
            especie = new Especie();
            if (i < 10) {
                especie.setMiCodigo("N-" + String.format("%1$06d", i));
            } else {
                especie.setMiCodigo("E-" + String.format("%1$06d", i));
            }
            especie.setMiNombre("NombreNuevo-" + String.format("%1$06d", i));
            especie.setMiDescripcionCastellano("descripción en castellano");
            especie.setMiDescripcionIngles("The description");
            especie.setMiDescripOrganicaCastellano("Descripción en castellano orgánica");
            especie.setMiDescripOrganicaIngles("The organic description");
            laLista.add(especie);
        }

        return laLista;
    }
 
    private static ArrayList<Variedad> simVariedades() {
        int cuantos = 5000;
        Variedad variedad;
        ArrayList<Variedad> laLista = new ArrayList<Variedad>(cuantos);
        for (int i = 0; i < cuantos; i++) {
            variedad = new Variedad();
            if (i < 10) {
                variedad.setMiCodigo("V-" + String.format("%1$06d", i));
            } else {
                variedad.setMiCodigo("V-" + String.format("%1$06d", i));
            }
            variedad.setMiDescripcion("Nombre-" + String.format("%1$06d", i));
            variedad.setMiDescVariedad1("descripción 1");
            variedad.setMiDescpcionVariedad2("segunda descrip");
            variedad.setMiEspecieCodigo("E-"+ String.format("%1$06d", i));
            laLista.add(variedad);
        }

        return laLista;
    }
    
    private static ArrayList<Envase> simEnvases() {
        int cuantos = 5000;
        Envase envase;
        ArrayList<Envase> laLista = new ArrayList<Envase>(cuantos);
        for (int i = 0; i < cuantos; i++) {
            envase = new Envase();
            if (i < 10) {
                envase.setMiCodigo("Enva-" + String.format("%1$03d", i));
            } else {
                envase.setMiCodigo("Enva-" + String.format("%1$03d", i));
            }
            envase.setMiDescripcion("NomEnv-" + String.format("%1$03d", i));
            envase.setMiDescripcion("descripción 1");
            envase.setMiDescripcion2("segunda descrip");
            envase.setMiEspecieCod("E-"+ String.format("%1$06d", i));
            envase.setMiTipoEnvase('A');
            laLista.add(envase);
        }

        return laLista;
    }

        private static ArrayList<Calibre> simCalibres() {
        int cuantos = 5;
        Calibre calibre;
        ArrayList<Calibre> laLista = new ArrayList<Calibre>(cuantos);
        for (int i = 0; i < cuantos; i++) {
            calibre = new Calibre();
            if (i < 10) {
                calibre.setMiTamanoCalibre("Cal-" + String.format("%1$03d", i));
            } else {
                calibre.setMiTamanoCalibre("Cal-" + String.format("%1$03d", i));
            }
            calibre.setMiEnvaseCod("Enva-" + String.format("%1$03d", i));
            calibre.setMiEspecieCod("E-" + String.format("%1$06d", i));
            laLista.add(calibre);
        }

        return laLista;
    }
        
    private static ArrayList<Embalaje> simEmbalajes() {
        int cuantos = 5000;
        Embalaje embalaje;
        ArrayList<Embalaje> laLista = new ArrayList<Embalaje>(cuantos);
        for (int i = 0; i < cuantos; i++) {
            embalaje = new Embalaje();
            if (i < 10) {
                embalaje.setMiCodigo("Emb-" + String.format("%1$03d", i));
            } else {
                embalaje.setMiCodigo("Emb-" + String.format("%1$03d", i));
            }
            embalaje.setMiDescripcion("NomEmba-" + String.format("%1$03d", i));
            embalaje.setMiEnvaseCod("Enva-" + String.format("%1$03d", i));
            embalaje.setMiEspecieCod("E-" + String.format("%1$06d", i));
            laLista.add(embalaje);
        }

        return laLista;
    }

        private static ArrayList<Almacen> simAlmacenes() {
        int cuantos = 5000;
        Almacen almacen;
        ArrayList<Almacen> laLista = new ArrayList<Almacen>(cuantos);
        for (int i = 0; i < cuantos; i++) {
            almacen = new Almacen();
            if (i < 10) {
                almacen.setMiCodigo("Alm-" + String.format("%1$03d", i));
            } else {
                almacen.setMiCodigo("Alm-" + String.format("%1$03d", i));
            }
            almacen.setMiDescripcion("descrip-" + String.format("%1$03d", i));
            almacen.setMiLugar("Lugar-" + String.format("%1$03d", i));
            laLista.add(almacen);
        }

        return laLista;
    }

        private static ArrayList<LeyendaEtiqueta> simLeyendas() {
        int cuantos = 5000;
        LeyendaEtiqueta leye;
        ArrayList<LeyendaEtiqueta> laLista = new ArrayList<LeyendaEtiqueta>(cuantos);
        for (int i = 0; i < cuantos; i++) {
            leye = new LeyendaEtiqueta();
            if (i < 10) {
                leye.setMiCodigo(String.format("%1$03d", i));
            } else {
                leye.setMiCodigo(String.format("%1$03d", i));
            }
            leye.setMiDescripcion("descrip-" + String.format("%1$03d", i));
            laLista.add(leye);
        }

        return laLista;
    }

    private static ArrayList<CodigoEAN> simEAN() {
        int cuantos = 12;
        CodigoEAN ean;
        ArrayList<CodigoEAN> laLista = new ArrayList<CodigoEAN>(cuantos);
        for (int i = 0; i < cuantos; i++) {
            ean = new CodigoEAN();
            String formato = "%1$0"+i+"d";
            if (i < 10) {
                ean.setMiCodigoArticulo("ArtEan-" + String.format(formato, i));
            } else {
                ean.setMiCodigoArticulo("ArtEan-" + String.format(formato, i));
            }
            ean.setMiEmbalajeCod("Emb-" + String.format("%1$03d", i));
            ean.setMiPesoEnvase(i);
            ean.setMiVariedadCod("V-" + String.format("%1$06d", i));
            ean.setMiEnvaseCod("Enva-" + String.format("%1$03d", i));
            ean.setMiMarcaCod("marca" + String.format("%1$03d", i));
            ean.setMiCategoriaCod("cate" + String.format("%1$03d", i));
            ean.setMiCodigo("123456"+ String.format("%1$03d", i));
            ean.setMiDescripcion1("Des1");
            ean.setMiDescripcion2("Des2");
            ean.setMiObservacion("observa");
            laLista.add(ean);
        }

        return laLista;
    }

        private static ArrayList<Contramarca> simContraMarca() {
        int cuantos = 5000;
        Contramarca contMarca;
        ArrayList<Contramarca> laLista = new ArrayList<Contramarca>(cuantos);
        for (int i = 0; i < cuantos; i++) {
            contMarca = new Contramarca();
            if (i < 10) {
                contMarca.setMiCodigo("ContMarca-" + String.format("%1$04d", i));
            } else {
                contMarca.setMiCodigo("ContMarca-" + String.format("%1$04d", i));
            }
            contMarca.setMiDescripcion("Descripacion/Contramarca-" + String.format("%1$03d", i));
            contMarca.setMiValorDefecto((i%2)==0);
            contMarca.setMiDescTarjeton("DescripTarjeton-" + String.format("%1$04d", i));
            contMarca.setMiTipotransporte(((i%2)==0) ? "MAR" : "AER");
            laLista.add(contMarca);
        }

        return laLista;
    }
    
        private static ArrayList<PesoStandar> simPesosStd() {
        int cuantos = 5000;
        PesoStandar pesoStd;
        ArrayList<PesoStandar> laLista = new ArrayList<PesoStandar>(cuantos);
        for (int i = 0; i < cuantos; i++) {
            pesoStd = new PesoStandar();
            pesoStd.setMiVariedadCod("V-" + String.format("%1$06d", i));
            pesoStd.setMiEnvaseCod("Enva-" + String.format("%1$03d", i));
            pesoStd.setMiEmbalajeCod("Emb-" + String.format("%1$03d", i));
            pesoStd.setMiCalibreCod("Cal" + String.format("%1$03d", i));
            pesoStd.setMiPosicion(i);
            pesoStd.setMiPeso(i+0.5);
            pesoStd.setMiMarca((i%2)==0);
            laLista.add(pesoStd);
        }

        return laLista;
    }

    private static ArrayList<Orden> simOrden() {
        int cuantos = 1000;
        Orden orden;
        long unDia = 86400000;//en milisegundos
        Date hoy = new Date();
        Date ffin;
        ArrayList<Orden> laLista = new ArrayList<Orden>(cuantos);
        for (int i = 0; i < cuantos; i++) {
            orden = new Orden();
            orden.setMiCodigo("Ord-" + String.format("%1$05d", i));
            orden.setMiEnvaseCod("Enva-" + String.format("%1$03d", i));
            orden.setMiEmbalajeCod("Emb-" + String.format("%1$03d", i));
            orden.setMiMaterialCod("ArtEan-" + String.format("%1$03d", i));
            orden.setMiEspecieCod("E-"+ String.format("%1$06d", i));
            orden.setMiVariedadCod("V-" + String.format("%1$06d", i));
            orden.setMiMarcaCod("marca" + String.format("%1$03d", i));
            orden.setMiCalidadCod("Cali" + String.format("%1$03d", i));
            orden.setMiCantidad(1);
            orden.setMisCajasPorPallet((i%2) == 0 ? 1 : i);
            orden.setMiFechaInicio(hoy);
            ffin = new Date();
            ffin.setTime(ffin.getTime()+((i+1)*unDia));
            orden.setMiFechaFin(ffin);
            laLista.add(orden);
        }

        return laLista;
    }

    private static ArrayList<Lote> simLote() {
        int cuantos = 5000;
        Lote lote;
        ArrayList<Lote> laLista = new ArrayList<Lote>(cuantos);
        for (int i = 0; i < cuantos; i++) {
            lote = new Lote();
            lote.setMiCodigo(String.format("%1$07d", i+100));
            lote.setMiEspecieCod("E-"+ String.format("%1$06d", i));
            lote.setMiVariedadCod("V-" + String.format("%1$06d", i));
            lote.setMiAtmosferaControlada("AM");
            lote.setMiProveedorNombre("Prov-" + String.format("%1$03d", i));
            lote.setMiSenasaCod("SSS");
            lote.setMiUmiCod("UMI-" + String.format("%1$03d", i));
            lote.setMiEuregapCoD("Euregap-" + String.format("%1$03d", i));
            lote.setMiCantidad(10.05);
            lote.setMiCantidadBins(i+200);
            laLista.add(lote);
        }

        return laLista;
    }*/
    
  /*  private void pruebas() {
        opServerProcess proceso = null;
        opVariableArray miArrayVar = new opVariableArray(1);
        try {
            miLogger.info("Incio Pruebas.");
            int cuantos = myProcess.CountUsers();
            cuantos = myProcess.CountUserProcesses();
            opServerProcessArray losProc = myProcess.GetProcessList();
//        int i = 0;
//        for (opServerProcess proc : losProc.mServerProcessArray) {
//            myProcess.GetProcessNumber(proc);
//            miLogger.info("info proceso "+ i + "----------");
//            miLogger.info("mProcessName : "+proc.mProcessName);
//            miLogger.info("mStationName : "+proc.mStationName);
//            miLogger.info("mProcessID : "+proc.mProcessID);
//            miLogger.info("mUserName : "+proc.mUserName);
//            miLogger.info("mUnique : "+proc.mUnique);
//            i++;
//        }
            
            for (opServerProcess proc : losProc.mServerProcessArray) {
                if (proc.mProcessName.equals("PruebaJava")) {
                    myProcess.GetProcessNumber(proc);
                    proceso = proc;
                    break;
                }
            }
        } catch (opException ex) {
          miLogger.info(ex.GetErrorMsg());
        }

        try {
            miArrayVar.mVariableArray[0] = new opVariable(opConstants.VPROCESS, "wadoint");
            myProcess.GetProcessVariable(proceso, miArrayVar);
        } catch (opException ex) {
          miLogger.info(ex.GetErrorMsg());
        }
        try {
            miArrayVar.mVariableArray[0] = new opVariable(opConstants.VPROCESS, "eli");
            myProcess.GetProcessVariable(proceso, miArrayVar);
        } catch (opException ex) {
          miLogger.info(ex.GetErrorMsg());
        }
        try {
            miArrayVar.mVariableArray[0] = new opVariable(opConstants.VPROCESS, "elreal");
            myProcess.GetProcessVariable(proceso, miArrayVar);
        } catch (opException ex) {
          miLogger.info(ex.GetErrorMsg());
        }
        try {
            miArrayVar.mVariableArray[0] = new opVariable(opConstants.VINTERPROCESS, "<>wx_cont");
            myProcess.GetProcessVariable(proceso, miArrayVar);
        } catch (opException ex) {
          miLogger.info(ex.GetErrorMsg());
        }
        try {
            miArrayVar.mVariableArray[0] = new opVariable(opConstants.VPROCESS, "wx_fecha");
            myProcess.GetProcessVariable(proceso, miArrayVar);
        } catch (opException ex) {
          miLogger.info(ex.GetErrorMsg());
        }
        try {
            miArrayVar.mVariableArray[0] = new opVariable(opConstants.VPROCESS, "wx_varString");
            myProcess.GetProcessVariable(proceso, miArrayVar);
        } catch (opException ex) {
          miLogger.info(ex.GetErrorMsg());
        }
        try {
            miArrayVar.mVariableArray[0] = new opVariable(opConstants.VPROCESS, "wadoflag");
            myProcess.GetProcessVariable(proceso, miArrayVar);
        } catch (opException ex) {
          miLogger.info(ex.GetErrorMsg());
        }
        try {
            miArrayVar.mVariableArray[0] = new opVariable(opConstants.VPROCESS, "elte");
            myProcess.GetProcessVariable(proceso, miArrayVar);
        } catch (opException ex) {
          miLogger.info(ex.GetErrorMsg());
        }
        try {
            miArrayVar.mVariableArray[0] = new opVariable(opConstants.VPROCESS, "otravariable");
            myProcess.GetProcessVariable(proceso, miArrayVar);
        } catch (opException ex) {
          miLogger.info(ex.GetErrorMsg());
        }
        try {
            miArrayVar.mVariableArray[0] = new opVariable(opConstants.VINTERPROCESS, "<>wfin");
            myProcess.GetProcessVariable(proceso, miArrayVar);            
        } catch (opException ex) {
          miLogger.info(ex.GetErrorMsg());
        }
        miLogger.info("---------");
    }*/
}
